﻿namespace AssemblyProvider.Web
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;
    using AssemblyProvider.Web.Entities;
    using AbstraX.ServerInterfaces;
    using System.IO;
    using System.Diagnostics;
    using MvvmTreeView;
    using System.Threading;
    using AbstraX.Contracts;
    using AbstraX.AssemblyInterfaces;
    using AbstraX.Bindings;
    using AbstraX.TypeMappings;
    using AbstraX;

    /*
        AssembliesRoot
          Assembly
            Type

              ---- Attributes

                     PropertyAttribute

              ---- Operations

                     ConstructorOperation
                     MethodOperation

              ---- ChildElements

                     PropertyElement
                       TypeElement
     */

    [EnableClientAccess()]
    public class AssemblyProviderService : DomainService, IAbstraXProviderService, IAssemblyProviderService
    {
        public IDomainHostApplication DomainServiceHostApplication { get; set; }

        [Invoke]
        public string GetRootID()
        {
            return new AssembliesRoot().ID;
        }

        public AssembliesRoot GetAssembliesRoot()
        {
            return new AssembliesRoot();
        }

        public IAssembliesRoot GetAssembliesRoot(List<string> assemblies)
        {
            return new AssembliesRoot(assemblies);
        }

        [Query]
        public IQueryable<Assembly> GetAssembliesForAssembliesRoot(string parentID)
        {
            Debug.WriteLine("Loading assemblies for '" + parentID + "'");

            var hierarchy = new AssemblyProviderHierarchy<Assembly>();
            var results = hierarchy.AsQueryable().Where(a => a.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Entities.AssemblyType> GetTypesForAssembly(string parentID)
        {
            Debug.WriteLine("Loading types for '" + parentID + "'");

            var hierarchy = new AssemblyProviderHierarchy<Entities.AssemblyType>(parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<PropertyElement> GetPropertyElementsForType(string parentID)
        {
            Debug.WriteLine("Loading property elements for '" + parentID + "'");

            var hierarchy = new AssemblyProviderHierarchy<PropertyElement>(parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<PropertyAttribute> GetPropertyAttributesForType(string parentID)
        {
            Debug.WriteLine("Loading property attributes for '" + parentID + "'");

            var hierarchy = new AssemblyProviderHierarchy<PropertyAttribute>(parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<FieldAttribute> GetFieldAttributesForType(string parentID)
        {
            Debug.WriteLine("Loading field attributes for '" + parentID + "'");

            var hierarchy = new AssemblyProviderHierarchy<FieldAttribute>(parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Operation> GetOperationsForType(string parentID)
        {
            Debug.WriteLine("Loading operation for '" + parentID + "'");

            var hierarchy = new AssemblyProviderHierarchy<Operation>(parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Entities.AssemblyType> GetTypesForType(string parentID)
        {
            Debug.WriteLine("Loading base types for '" + parentID + "'");

            var hierarchy = new AssemblyProviderHierarchy<Entities.AssemblyType>(parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Entities.AssemblyType> GetTypesForPropertyElement(string parentID)
        {
            Debug.WriteLine("Loading types for property element '" + parentID + "'");

            var hierarchy = new AssemblyProviderHierarchy<Entities.AssemblyType>(parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Invoke]
        public byte[] GetImageForFolder(string folderKey)
        {
            Debug.WriteLine("Loading images for '" + folderKey + "'");

            var stream = this.GetType().Assembly.GetManifestResourceStream(folderKey);
            var bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int)stream.Length);

            return bytes;
        }

        [Invoke]
        public byte[] GetImageForItemType(string itemTypeName)
        {
            Debug.WriteLine("Loading images for '" + itemTypeName + "'");

            var attribute = (NodeImageAttribute) System.Type.GetType(itemTypeName).GetCustomAttributes(true).FirstOrDefault(a => a is NodeImageAttribute);

            var stream = this.GetType().Assembly.GetManifestResourceStream(attribute.ImagePath);
            var bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int) stream.Length);

            return bytes;
        }

        [Invoke]
        public byte[] GetImageForUrl(string url)
        {
            Debug.WriteLine("Loading images for '" + url + "'");

            var stream = this.GetType().Assembly.GetManifestResourceStream(url);
            var bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int)stream.Length);

            return bytes;
        }

        public IBase GenerateByID(string id)
        {
            return AbstraXExtensions.GenerateByID(this, id);
        }

        public ContainerType GetAllowableContainerTypes(string id)
        {
            var baseObject = AbstraXExtensions.GenerateByID(this, id);

            throw new NotImplementedException();
        }

        public ConstructType GetAllowableConstructTypes(string id)
        {
            var baseObject = AbstraXExtensions.GenerateByID(this, id);

            throw new NotImplementedException();
        }

        public SortedList<float, IPipelineStep> InitialPipelineSteps
        {
            get 
            {
                return null;
            }
        }
    }
}


